import javax.swing.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.CharBuffer;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


public class SocketServe {

    private final static String SOAP_BEGIN = "<SOAP>";
    private final static String SOAP_END = "</SOAP>";
    private static GameGUI gameGUI;
    private static Integer PORT = 8080;
    private static Integer count = 0;//连接数
    Map<String, Socket> socketMap = new ConcurrentHashMap<>();
    StrategyFactory strategyFactory = new StrategyFactory();
    private SendThread sendThread;

    public void setMsg(String msg) {
        if (null != sendThread)
            sendThread.setMsg(msg);
    }

    public SocketServe(GameGUI gameGUI, Integer port) {
        this.gameGUI = gameGUI;
        this.PORT = port;
    }

    public void addListener(String eventName, EventApi eventApi) {
        strategyFactory.strategyMaps.put(eventName, eventApi);
    }

    public static void main(String[] args) throws IOException {
        SocketServe socketServer = new SocketServe(gameGUI, 8088);
        socketServer.start();
    }

    public void start() throws IOException {
        ServerSocket serverSocket = new ServerSocket(PORT);
        System.out.println("服务端启动成功 端口：" + PORT);
        addListener("gameOver", new EventApi() {
            @Override
            public void doEvent(Message message) {
                gameGUI.jButtons.get(2).setEnabled(false); // 认输不可用
                Integer type = message.getType();
                gameGUI.getjLabel()[0].setText(type == gameGUI.getChessType()?"你赢了":"你输了");

//                JOptionPane.showMessageDialog(null,
//                        type == gameGUI.getChessType()?"你赢了":"你输了",
//                        type == gameGUI.getChessType()?"恭喜":"",
//                        JOptionPane.DEFAULT_OPTION);
            }
        });
        addListener("giveup", new EventApi() {
            @Override
            public void doEvent(Message message) {
                gameGUI.jButtons.get(2).setEnabled(false); // 认输不可用
                gameGUI.getjLabel()[1].setText("你赢了");

//                JOptionPane.showMessageDialog(null,
//                        "你赢了",
//                        "恭喜",
//                        JOptionPane.DEFAULT_OPTION);
//                System.out.println(message.getType() + "认输");
            }
        });
        addListener("msg", new EventApi() {
            @Override
            public void doEvent(Message message) {
                JLabel jLabel = gameGUI.getjLabel()[0];
                Integer type = message.getType();
                if (type == 1) {// 黑棋发来的消息
                    jLabel.setText("现在是白棋下");
                } else if (type == 2) {
                    jLabel.setText("现在是黑棋下");
                }
                String content = message.getContent();
                gameGUI.getChess().Edge = ArrayUtils.JSON2Array(content);
                gameGUI.repaint();
                gameGUI.setChessFlag(true);
            }
        });
        // 开始
        addListener("reGame", new EventApi() {
            @Override
            public void doEvent(Message message) {
                JLabel jLabel = gameGUI.getjLabel()[0];
                Integer type = Integer.valueOf(message.getContent());
                gameGUI.setType(type);
                if (type == 1) {// 黑棋先行
                    gameGUI.setChessFlag(true);
                    jLabel.setText("现在是黑棋下");
                    gameGUI.getjLabel()[1].setText("你是黑棋");
                } else if (type == 2) {
                    jLabel.setText("现在是黑棋下");
                    gameGUI.getjLabel()[1].setText("你是白棋");
                }
                gameGUI.getChess().reset();
                gameGUI.repaint();
                gameGUI.setStart(true);
                gameGUI.jButtons.get(2).setEnabled(true);
                // 游戏开始后开始和准备按钮不可点击
                gameGUI.jButtons.get(3).setEnabled(false);
                gameGUI.jButtons.get(4).setEnabled(false);
            }
        });
        //
        addListener("reading", new EventApi() {
            @Override
            public void doEvent(Message message) {
                JButton jButton = gameGUI.jButtons.get(3);
                jButton.setVisible(true);
                gameGUI.setReady(true);
                gameGUI.jButtons.get(3).setEnabled(true); //开始按钮
            }
        });
        sendThread = new SendThread();
        new Thread(sendThread).start();
        JButton createBtn = gameGUI.jButtons.get(0);
        createBtn.setEnabled(false);
        createBtn.setText("创建成功");
        while (true) {
            Socket socket = serverSocket.accept();
            count++;
            new SocketThread(socket).start();
        }
    }

    //发送消息线程
    class SendThread implements Runnable {
        private Message message = new Message();
        private volatile Integer flag = 0;

        @Override
        public void run() {
            String msg;
            while (true) {
                msg = message.getContent();
                if (flag == 1 && null != msg)
                    try {
                        Set<String> strings = socketMap.keySet();
                        String finalMsg = msg;
                        strings.parallelStream().forEach(s -> {
                            Socket socket = socketMap.get(s);
                            try {

                                Writer writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "GBK"));
                                writer.write(SOAP_BEGIN + finalMsg + SOAP_END);
                                writer.flush();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        });
                        message.setContent(null);
                        flag = 0;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
        }

        public void setMsg(String msg) {
            message.setType(gameGUI.getChessType());
            message.setEventName("msg");
            message.setContent(msg);
            flag = 1;
        }
    }

    // 读取消息线程
    class SocketThread extends Thread {
        private Socket socket;
        private String temp = "";

        public Socket getSocket() {
            return socket;
        }

        public void setSocket(Socket socket) {
            this.socket = socket;
        }

        public SocketThread(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {
                Reader reader = new InputStreamReader(socket.getInputStream());
                Writer writer = new PrintWriter(new OutputStreamWriter(socket
                        .getOutputStream(), "GBK"));
                CharBuffer charBuffer = CharBuffer.allocate(8192);
                String hostAddress = socket.getInetAddress().getHostAddress();
                socketMap.put(hostAddress, socket);
                int readIndex = -1;
                while ((readIndex = reader.read(charBuffer)) != -1) {
                    charBuffer.flip();
                    temp += charBuffer.toString();
                    // 判断报文是否有开始和结束标签
                    if (temp.indexOf(SOAP_END) != -1 && temp.indexOf(SOAP_BEGIN) != -1) {
                        String s = temp.replaceAll(SOAP_BEGIN, "");
                        s = s.replaceAll(SOAP_END, "");
                        Message message = ArrayUtils.jsonToMessage(s);
                        strategyFactory.getApiByFuncName(message.getEventName()).doEvent(message);
                        temp = "";
                    }
                    if (temp.length() > 1024 * 16) {
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (socket != null) {
                    if (!socket.isClosed()) {
                        try {
                            socket.close();
                            // 从集合中删除socket
                            String hostAddress = socket.getInetAddress().getHostAddress();
                            socketMap.remove(hostAddress);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }
    }
}